import os
import platform
import tkinter as tk
from PIL import ImageTk
from tkinter import messagebox
from tkinter import filedialog
import socket
import time
import _thread
import threading
import logging
import datetime
import logging



###############################################################################
# 全局变量
g_ips = []
camera_found = 0
cameras_found = 0       # 记录所有查找到的相机数量


###############################################################################
# 日志模块
class LogHandler(logging.Handler):
    def __init__(self, text_widget):
        logging.Handler.__init__(self)
        self.text_widget = text_widget

    def emit(self, record):
        msg = self.format(record)
        self.text_widget.insert(tk.END, msg + '\n')
        self.text_widget.see(tk.END)

###############################################################################


class mephisto_mosaic_camera:
    def __init__(self, IP='10.75.0.30', SOCK_PORT='9527'):
        self.lcoal_ip   = IP
        self.sock_port  = SOCK_PORT
        self.camera_ips = []                    # 记录发现的相机IP

        self.window = tk.Tk()
        # self.window.title('Camera Python')    # 设置窗口的标题
        self.window.geometry('900x800')         # 设置窗口的大小
        self.window.resizable(0,0)

        # self.window.iconbitmap('webcamoid.ico')
        # self.window.iconphoto(False, tk.PhotoImage(file='camera.png'))
        # self.window.iconphoto(True,tk.PhotoImage(file='camera.png'))
        self.window.iconphoto(False,tk.PhotoImage(file='./icon/camera.png'))

        self.window.wm_title("Mephisto Mosaic Camera GUI")

        ######################################################################
        # IP网段和端口输入对话框标签
        tk.Label(self.window, text="HOST IP:", bg='gold').place(x=15, y=20, height=30, anchor='nw')
        tk.Label(self.window, text="PORT:", bg='gold').place(x=250, y=20, height=30, anchor='nw')

        # IP网段和端口输入对话框
        self.host_ip_var = tk.StringVar()
        self.host_port_var = tk.StringVar()
        self.en1 = tk.Entry(self.window, textvariable=self.host_ip_var)
        self.en2 = tk.Entry(self.window, textvariable=self.host_port_var)

        self.en1.place(x=75, y=20, width=100, height=30, anchor='nw')
        self.en1.insert(0, self.lcoal_ip)

        self.en2.place(x=300, y=20, width=60, height=30, anchor='nw')
        self.en2.insert(0, self.sock_port)

        # 添加搜索相机的按钮
        self.btn_search_cam = tk.Button(self.window, text='Find Camera', bg='gold', command=self.socket_find_camera)
        self.btn_search_cam.place(x=500, y=20, width=120, height=30, anchor='ne')

        # 复位配置按钮
        self.btn_reset_config = tk.Button(self.window, text='Reset Config', bg='gray', command=self.reset_config)
        self.btn_reset_config.place(x=800, y=20, width=120, height=30, anchor='ne')        

        ######################################################################
        # 相机1~4的IP输入端口
        self.ip_var_camera1 = tk.StringVar()
        self.ip_var_camera2 = tk.StringVar()
        self.ip_var_camera3 = tk.StringVar()
        self.ip_var_camera4 = tk.StringVar()
        self.ip_var_master  = tk.StringVar()
        self.ip_var_master_is_set = False

        self.entry_ip_var_camera1 = tk.Entry(self.window, textvariable=self.ip_var_camera1)
        self.entry_ip_var_camera2 = tk.Entry(self.window, textvariable=self.ip_var_camera2)
        self.entry_ip_var_camera3 = tk.Entry(self.window, textvariable=self.ip_var_camera3)
        self.entry_ip_var_camera4 = tk.Entry(self.window, textvariable=self.ip_var_camera4)
        self.entry_ip_var_master  = tk.Entry(self.window, textvariable=self.ip_var_master)

        self.entry_ip_var_camera1.insert(0, '')
        self.entry_ip_var_camera2.insert(0, '')
        self.entry_ip_var_camera3.insert(0, '')
        self.entry_ip_var_camera4.insert(0, '')
        self.entry_ip_var_master.insert(0, '')

        # 相机1~4的master/slave状态
        self.role_var_camera1   = tk.StringVar()
        self.role_var_camera2   = tk.StringVar()
        self.role_var_camera3   = tk.StringVar()
        self.role_var_camera4   = tk.StringVar()
        self.entry_master_status1 = tk.Entry(self.window, textvariable=self.role_var_camera1)
        self.entry_master_status2 = tk.Entry(self.window, textvariable=self.role_var_camera2)
        self.entry_master_status3 = tk.Entry(self.window, textvariable=self.role_var_camera3)
        self.entry_master_status4 = tk.Entry(self.window, textvariable=self.role_var_camera4)

        # 相机1~4的mount路径
        self.bindir_camera1_val = tk.StringVar()
        self.bindir_camera2_val = tk.StringVar()
        self.bindir_camera3_val = tk.StringVar()
        self.bindir_camera4_val = tk.StringVar()
        self.bindir_camera1 = tk.Entry(self.window, textvariable=self.bindir_camera1_val)
        self.bindir_camera2 = tk.Entry(self.window, textvariable=self.bindir_camera2_val)
        self.bindir_camera3 = tk.Entry(self.window, textvariable=self.bindir_camera3_val)
        self.bindir_camera4 = tk.Entry(self.window, textvariable=self.bindir_camera4_val)

        
        # 设置在界面的位置
        self.lbl_cam1 = tk.Label(self.window, text="CAM-1", bg='gray')
        self.lbl_cam1.place(x=15, y=60, height=30, anchor='nw')
        self.entry_ip_var_camera1.place(x=75, y=60, width=100, height=30, anchor='nw')
        self.btn_cam1_set_master = tk.Button(self.window, text='Set as Master', state=tk.DISABLED, command=self.socket_set_cam1_as_master)
        self.btn_cam1_set_master.place(x=280, y=60, width=95, height=30, anchor='ne')
        self.entry_master_status1.place(x=300, y=60, width=60, height=30, anchor='nw')
        self.btn_cam1_mount = tk.Button(self.window, text='Mount Linux Host', state=tk.DISABLED, command=self.socket_set_linuxhost_bindir_cam1)
        self.btn_cam1_mount.place(x=500, y=60, width=120, height=30, anchor='ne')
        self.bindir_camera1.place(x=520, y=60, width=350, height=30, anchor='nw')

        self.lbl_cam2 = tk.Label(self.window, text="CAM-2", bg='gray')
        self.lbl_cam2.place(x=15, y=95, height=30, anchor='nw')
        self.entry_ip_var_camera2.place(x=75, y=95, width=100, height=30, anchor='nw')
        self.btn_cam2_set_master = tk.Button(self.window, text='Set as Master', state=tk.DISABLED, command=self.socket_set_cam2_as_master)
        self.btn_cam2_set_master.place(x=280, y=95, width=95, height=30, anchor='ne')
        self.entry_master_status2.place(x=300, y=95, width=60, height=30, anchor='nw')
        self.btn_cam2_mount = tk.Button(self.window, text='Mount Linux Host', state=tk.DISABLED, command=self.socket_find_camera)
        self.btn_cam2_mount.place(x=500, y=95, width=120, height=30, anchor='ne')
        self.bindir_camera2.place(x=520, y=95, width=350, height=30, anchor='nw')

        self.lbl_cam3 = tk.Label(self.window, text="CAM-3", bg='gray')
        self.lbl_cam3.place(x=15, y=130, height=30, anchor='nw')
        self.entry_ip_var_camera3.place(x=75, y=130, width=100, height=30, anchor='nw')
        self.btn_cam3_set_master = tk.Button(self.window, text='Set as Master', state=tk.DISABLED, command=self.socket_set_cam3_as_master)
        self.btn_cam3_set_master.place(x=280, y=130, width=95, height=30, anchor='ne')
        self.entry_master_status3.place(x=300, y=130, width=60, height=30, anchor='nw')
        self.btn_cam3_mount = tk.Button(self.window, text='Mount Linux Host', state=tk.DISABLED, command=self.socket_find_camera)
        self.btn_cam3_mount.place(x=500, y=130, width=120, height=30, anchor='ne')
        self.bindir_camera3.place(x=520, y=130, width=350, height=30, anchor='nw')

        self.lbl_cam4 = tk.Label(self.window, text="CAM-4", bg='gray')
        self.lbl_cam4.place(x=15, y=165, height=30, anchor='nw')
        self.entry_ip_var_camera4.place(x=75, y=165, width=100, height=30, anchor='nw')
        self.btn_cam4_set_master = tk.Button(self.window, text='Set as Master', state=tk.DISABLED, command=self.socket_set_cam4_as_master)
        self.btn_cam4_set_master.place(x=280, y=165, width=95, height=30, anchor='ne')
        self.entry_master_status4.place(x=300, y=165, width=60, height=30, anchor='nw')
        self.btn_cam4_mount = tk.Button(self.window, text='Mount Linux Host', state=tk.DISABLED, command=self.socket_find_camera)
        self.btn_cam4_mount.place(x=500, y=165, width=120, height=30, anchor='ne')
        self.bindir_camera4.place(x=520, y=165, width=350, height=30, anchor='nw')

        self.lbl_master = tk.Label(self.window, text="MASTER", bg='gray')
        self.lbl_master.place(x=10, y=200, height=30, anchor='nw')
        self.entry_ip_var_master.place(x=75, y=200, width=100, height=30, anchor='nw')

        ######################################################################
        # Linux host挂载目录
        self.btn_host_dir = tk.Button(self.window, text="Linux Host Dir", bg='gray', state=tk.DISABLED, command=self.thread_socket_set_LinuxHostBinDir)
        self.btn_host_dir.place(x=500, y=200, width=120, height=30, anchor='ne')
        self.linux_host_bindir          = tk.StringVar()
        self.entry_linux_host_bindir    = tk.Entry(self.window, textvariable=self.linux_host_bindir)
        self.entry_linux_host_bindir.insert(0, "Click 'Linux Host Dir' to choose a host mount point")
        self.entry_linux_host_bindir.configure(state=tk.DISABLED)
        self.entry_linux_host_bindir.place(x=520, y=200, width=350, height=30, anchor='nw')


        # 添加socket连接确认按钮
        tk.Button(self.window, text='Check Host Connection', command=self.socket_check_host_connection).place(x=20, y=275)

        # 添加曝光/终止曝光按钮
        # tk.Button(self.window, text='Exposure', command=self.socket_exposure).place(x=20, y=350)
        self.var_expt = tk.StringVar()
        self.var_expt.set('0')
        self.entry_expt = tk.Entry(self.window, textvariable=self.var_expt);
        self.entry_expt.place(x=20, y=350, width=100, height=30, anchor='nw')

        self.btn_set_expt = tk.Button(self.window, text='Set ExpTime', command=self.socket_set_exposure_time)
        self.btn_set_expt.place(x=150, y=350, width=80, height=30)
        self.btn_exp = tk.Button(self.window, text='Exposure', command=self.socket_master_exposure)
        self.btn_exp.place(x=300, y=350, height=30)
        # self.btn_exp.configure(bg='green')
        self.btn_exp.configure(state=tk.DISABLED, bg='gray')

        self.btn_abort_exp = tk.Button(self.window, text='AbortExp', height=30, command=self.socket_abort)
        self.btn_abort_exp.place(x=450, y=350, height=30)
        self.btn_abort_exp.configure(state=tk.DISABLED, bg='gray')

        # 添加退出按钮
        self.btn_exit = tk.Button(self.window, text='Exit', command=self.window.quit)
        self.btn_exit.place(x=820, y=350, anchor='nw')

        # 添加日志输出对话框
        # self.text_widget = tk.Text(self.window).place(x=20, y=200)
        self.text_widget = tk.Text(self.window)
        self.text_widget.pack(side='bottom', fill='x')
        self.log_handler = LogHandler(self.text_widget)
        # 创建日志记录器
        self.logger = logging.getLogger()
        self.logger.addHandler(self.log_handler)
        self.logger.setLevel(logging.INFO)
        self.logger.info('Start logging...')

    def write_log(self, msg):
        # logmsg = '{}:> {}'.format(datetime.datetime.now(), msg)
        # logmsg = '{}:> {}'.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), msg)
        logmsg = '{}:> {}'.format(datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3], msg)
        self.logger.info(logmsg)

    # 以下是与各按钮对应的线程函数
    def thread_find_camera(self):
        camera_found = 0 # DONOT forget to reset it to zero
        self.camera_ips = []
        self.ip_var_camera1.set('')
        self.ip_var_camera2.set('')
        self.ip_var_camera3.set('')
        self.ip_var_camera4.set('')
        self.ip_var_master.set('')

        addr = self.host_ip_var.get()
        args = "".join(addr)
        ip_pre = '.'.join(args.split('.')[:-1])

        self.write_log('Start searching Camera in local network {}.xxx'.format(ip_pre))

        ips = [ip_pre+'.{}'.format(i) for i in range(100,256)]
        # print('ips: {}'.format(ips))
        
        for ip in ips:
            self.write_log('trying IP: {}'.format(ip))
            try:
                # local_sock = socket.socket()
                local_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                local_sock.settimeout(0.02)                                     # 这个非常重要
                local_sock.connect( (ip, int(self.host_port_var.get())) )

                cmd = 'whoareyou'
                local_sock.send(cmd.encode('utf-8'))

                while True:
                    recv = local_sock.recv(1024)
                    recv_str = recv.decode('utf-8')
                    if recv_str.find('Blue1') != -1:  # TODO: 这里以后要进行修改
                        local_sock.send('exit'.encode('utf-8'))
                        camera_found += 1 
#                        self.ip_var.set(ip)
                        self.camera_ips.append(ip)
                        break

                    if recv_str.find('Blue2') != -1:  # TODO: 这里以后要进行修改
                        local_sock.send('exit'.encode('utf-8'))
                        camera_found += 1
#                        self.ip_var.set(ip)
                        self.camera_ips.append(ip)
                        break

                    if recv_str.find('Blue3') != -1:  # TODO: 这里以后要进行修改
                        local_sock.send('exit'.encode('utf-8'))
                        camera_found += 1
#                        self.ip_var.set(ip)
                        self.camera_ips.append(ip)
                        break

                    if recv_str.find('Blue4') != -1:  # TODO: 这里以后要进行修改
                        local_sock.send('exit'.encode('utf-8'))
                        camera_found += 1
#                        self.ip_var.set(ip)
                        self.camera_ips.append(ip)
                        break

                    # if len(self.camera_ips) == 4:
                    #     break


                local_sock.close()

            except:
                pass

            if camera_found != 0:
                break

        if camera_found == 0:
            self.write_log('*****************************')
            self.write_log('****   No camera found! *****')
            self.write_log('**** CHECK YOUR INPUT IP ****')
            self.write_log('*****************************')
        else:
            self.write_log('Found the Camera:')
            for i in range(len(self.camera_ips)):
                self.write_log('CAM{} IP: {}'.format(i+1, self.camera_ips[i]))

            self.camera_ips = ['192.168.0.104','192.168.0.106','192.168.0.107', '192.168.0.108']
            
            self.write_log('self.camera_found : {}'.format(camera_found))

            self.btn_search_cam.configure(bg='lime')
            self.btn_reset_config.configure(bg='cornflowerblue')

            self.btn_host_dir.configure(state=tk.NORMAL)
            self.btn_exit.configure(bg='brown')

            self.btn_exp.configure(state=tk.NORMAL, bg='green')


            if len(self.camera_ips) == 1:
                self.ip_var_camera1.set(self.camera_ips[0])
                self.btn_cam1_set_master.configure(state=tk.NORMAL)
                self.btn_cam1_mount.configure(state=tk.NORMAL)
                self.lbl_cam1.configure(bg='lime')
            elif len(self.camera_ips) == 2:
                self.ip_var_camera1.set(self.camera_ips[0])
                self.btn_cam1_set_master.configure(state=tk.NORMAL)
                self.btn_cam1_mount.configure(state=tk.NORMAL)
                self.lbl_cam1.configure(bg='lime')

                self.ip_var_camera2.set(self.camera_ips[1])
                self.btn_cam2_set_master.configure(state=tk.NORMAL)
                self.btn_cam2_mount.configure(state=tk.NORMAL)
                self.lbl_cam2.configure(bg='lime')
            elif len(self.camera_ips) == 3:
                self.ip_var_camera1.set(self.camera_ips[0])
                self.btn_cam1_set_master.configure(state=tk.NORMAL)
                self.btn_cam1_mount.configure(state=tk.NORMAL)
                self.lbl_cam1.configure(bg='lime')

                self.ip_var_camera2.set(self.camera_ips[1])
                self.btn_cam2_set_master.configure(state=tk.NORMAL)
                self.btn_cam2_mount.configure(state=tk.NORMAL)
                self.lbl_cam2.configure(bg='lime')

                self.ip_var_camera3.set(self.camera_ips[2])
                self.btn_cam3_set_master.configure(state=tk.NORMAL)
                self.btn_cam3_mount.configure(state=tk.NORMAL)
                self.lbl_cam3.configure(bg='lime')

            elif len(self.camera_ips) == 4:
                self.ip_var_camera1.set(self.camera_ips[0])
                self.btn_cam1_set_master.configure(state=tk.NORMAL)
                self.btn_cam1_mount.configure(state=tk.NORMAL)
                self.lbl_cam1.configure(bg='lime')
                
                self.ip_var_camera2.set(self.camera_ips[1])
                self.btn_cam2_set_master.configure(state=tk.NORMAL)
                self.btn_cam2_mount.configure(state=tk.NORMAL)
                self.lbl_cam2.configure(bg='lime')
                
                self.ip_var_camera3.set(self.camera_ips[2])
                self.btn_cam3_set_master.configure(state=tk.NORMAL)
                self.btn_cam3_mount.configure(state=tk.NORMAL)
                self.lbl_cam3.configure(bg='lime')

                self.ip_var_camera4.set(self.camera_ips[3])
                self.btn_cam4_set_master.configure(state=tk.NORMAL)
                self.btn_cam4_mount.configure(state=tk.NORMAL)
                self.lbl_cam4.configure(bg='lime')


    def reset_config(self):
        self.write_log('Start clearing configurations ...')
        self.btn_search_cam.configure(bg='gold')
        self.ip_var_camera1.set('')
        self.ip_var_camera2.set('')
        self.ip_var_camera3.set('')
        self.ip_var_camera4.set('')
        self.ip_var_master.set('')
        self.ip_var_master_is_set = False

        self.role_var_camera1.set('')
        self.role_var_camera2.set('')
        self.role_var_camera3.set('')
        self.role_var_camera4.set('')

        self.lbl_cam1.configure(bg='gray')
        self.lbl_cam2.configure(bg='gray')
        self.lbl_cam3.configure(bg='gray')
        self.lbl_cam4.configure(bg='gray')


        self.btn_cam1_set_master.configure(state=tk.DISABLED)
        self.btn_cam2_set_master.configure(state=tk.DISABLED)
        self.btn_cam3_set_master.configure(state=tk.DISABLED)
        self.btn_cam4_set_master.configure(state=tk.DISABLED)
        self.lbl_master.configure(bg='gray')


        self.btn_cam1_mount.configure(state=tk.DISABLED)
        self.btn_cam2_mount.configure(state=tk.DISABLED)
        self.btn_cam3_mount.configure(state=tk.DISABLED)
        self.btn_cam4_mount.configure(state=tk.DISABLED)

        self.linux_host_bindir.set("")
        self.btn_host_dir.configure(bg='gray')
        self.btn_host_dir.configure(state=tk.DISABLED)
        self.entry_linux_host_bindir.configure(state=tk.DISABLED)

        self.btn_exp.configure(state=tk.DISABLED, bg='gray')

        self.ip_var_master_is_set = False

        self.btn_reset_config.configure(bg='gray')
        self.write_log('Finished clearing configurations')


    def thread_check_host_connection(self):
        try:
            cmd = 'check_connection'
            local_sock = socket.socket()
            # local_sock.settimeout(0.02)                                         # 这个非常重要
            local_sock.connect((self.host_ip_var.get(), int(self.host_port_var.get())))
            local_sock.send(cmd.encode('utf-8'))

            while True:
                recv = local_sock.recv(1024)
                recv_str = recv.decode('utf-8')

                if recv_str.find('check_connection_ok') != -1:
                    local_sock.send('exit'.encode('utf-8'))
                    self.write_log('host connection is OK')
                    break
        except:
            self.write_log('socket connecttion failed.')


    def thread_socket_command(self,thread_name, cmd):
        try:
            local_sock = socket.socket()
            # local_sock.settimeout(0.02)                                         # 这个非常重要，但是放在这里会出问题
            local_sock.connect((self.host_ip_var.get(), int(self.host_port_var.get())))
            local_sock.send(cmd.encode('utf-8'))
            self.write_log('send cmd: {}'.format(cmd))

            while True:
                recv = local_sock.recv(1024)
                recv_str = recv.decode('utf-8')
                if recv_str.find(cmd+'_ok') != -1:
                    local_sock.send('exit'.encode('utf-8'))
                    self.write_log('close socket({}) on thread({})'.format(local_sock.fileno(), _thread.get_native_id()))
                    break
        except:
            self.write_log('socket connecttion failed.')


    def thread_socket_ip_command(self, ip='', thread_name='', cmd=''):
        try:
            local_sock = socket.socket()
            # local_sock.settimeout(0.02)                           # 这个非常重要，但是放在这里会出问题
            local_sock.connect((ip, int(self.host_port_var.get())))      # 遇到一个奇怪的问题，即使IP为空，也能正常连接至测试时的IP
            local_sock.send(cmd.encode('utf-8'))

            if cmd.find('exposure') != -1:
                self.btn_exp.configure(state=tk.DISABLED, bg='gray')

            wait_cnt = 0
            while True:
                recv = local_sock.recv(1024)
                recv_str = recv.decode('utf-8')
                # for debug 
                # self.write_log('> recieved: -{}-'.format(recv_str))
                # self.write_log('> recv_str.find(cmd+\'_ok\') = {}'.format(recv_str.find(cmd+'_ok')))

                # if recv_str.find(cmd+'_ok') != -1:
                if recv_str.find(cmd+'_ok') != -1:
                    """
                    @2024-10-07:
                    在这里犯了一个非常低级的SB错误:如果给服务端发送的指令是复合的,类似'set_exp_t|3.0'这种,服务端按照预期的方式
                    进行解析并执行了操作,但是返回的消息却是set_exp_t_ok.然而在这里利用recv_str.find(cmd+'_ok')进行比较的时候,
                    cmd+'_ok'中的内容实际是'set_exp_t|3.0_ok',因此recv_str.find(cmd+'_ok')的返回值必然是-1,这里后续的代码
                    自然不会执行,服务端那边收不到exit指令,线程函数自然不会退出了!!!
                    为了保险起见,服务端在完成一个指令后,返回的信息全部用recvbuf+'_ok'这种组合方式进行.
                    """
                    # local_sock.send(('exit|\n').encode('utf-8'))
                    local_sock.send('exit'.encode('utf-8'))
                    # self.write_log('send exit to server')
                    # self.write_log('{} on thread({}) is executed'.format(thread_name, _thread.get_native_id()))

                    if cmd.find('exposure') != -1:
                        self.btn_exp.configure(state=tk.NORMAL, bg='green')

                    break

                # wait_cnt += 1
                # time.sleep(1)
                # if wait_cnt > 5:
                #     self.write_log('thread({}) exit due to long time no repsponse from socket server...'.format(_thread.get_native_id()))
                #     break
        except:
            self.write_log('socket connecttion failed.')

    def thread_socket_ip_exposure(self, ip='', thread_name='', cmd=''):
        """
        曝光时需要将按钮禁用,这个与其他指令有所不同,因此单独定义这个专用的函数
        """
        try:
            local_sock = socket.socket()
            # local_sock.settimeout(0.02)                           # 这个非常重要，但是放在这里会出问题
            local_sock.connect((ip, int(self.host_port_var.get())))      # 遇到一个奇怪的问题，即使IP为空，也能正常连接至测试时的IP
            local_sock.send(cmd.encode('utf-8'))
            self.write_log('expsoure begins')
            self.btn_exp.configure(state=tk.DISABLED, bg='gray')
            self.btn_abort_exp.configure(state=tk.NORMAL, bg='red')

            wait_cnt = 0
            while True:
                recv = local_sock.recv(1024)
                recv_str = recv.decode('utf-8')
                if recv_str.find(cmd+'_ok') != -1:
                    local_sock.send('exit'.encode('utf-8'))
                    self.write_log('expsoure ends')
                    self.btn_exp.configure(state=tk.NORMAL, bg='green')
                    self.btn_abort_exp.configure(state=tk.DISABLED, bg='gray')
                    break
        except:
            self.write_log('socket connecttion failed.')

#   设置各相机的输出文件名
    def thread_socket_set_binfilename(self):
        pass

#   设置Linux主机挂载目录，存放bin文件
    def thread_socket_set_LinuxHostBinDir(self):
        self.entry_linux_host_bindir.configure(state=tk.NORMAL)
        self.write_log('updating Linux Host Dir...')
        self.linux_host_bindir.set(filedialog.askdirectory())
        self.write_log('new host dir: {}'.format(self.linux_host_bindir.get()))
        self.btn_host_dir.configure(bg='lime')


#   设置master/slave
    def thread_socket_set_cam1_as_master(self):
        if len(self.ip_var_camera1.get()) > 0:
            # send command 'set_as_master'
            self.thread_socket_ip_command(self.ip_var_camera1.get(), 'thread_socket_set_cam1_as_master', 'set_as_master')
            self.write_log('set CAM-1 as master')
            self.role_var_camera1.set('Master')
            self.ip_var_master.set(self.ip_var_camera1.get())
            self.lbl_master.configure(bg='lime')
            self.ip_var_master_is_set = True
        
        if len(self.ip_var_camera2.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera2.get(), 'thread_socket_set_cam1_as_master', 'set_as_slave')
            self.write_log('set CAM-2 as slave')
            self.role_var_camera2.set('Slave')

        if len(self.ip_var_camera3.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera3.get(), 'thread_socket_set_cam1_as_master', 'set_as_slave')
            self.write_log('set CAM-3 as slave')
            self.role_var_camera3.set('Slave')

        if len(self.ip_var_camera4.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera4.get(), 'thread_socket_set_cam1_as_master', 'set_as_slave')
            self.write_log('set CAM-4 as slave')
            self.role_var_camera4.set('Slave')

    def thread_socket_set_cam2_as_master(self):
        if len(self.ip_var_camera2.get()) > 0:
            # send command 'set_as_master'
            self.thread_socket_ip_command(self.ip_var_camera2.get(), 'thread_socket_set_cam2_as_master', 'set_as_master')
            self.write_log('set CAM-2 as master')
            self.role_var_camera2.set('Master')
            self.ip_var_master.set(self.ip_var_camera2.get())
            self.lbl_master.configure(bg='lime')
            self.ip_var_master_is_set = True
        
        if len(self.ip_var_camera1.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera1.get(), 'thread_socket_set_cam2_as_master', 'set_as_slave')
            self.write_log('set CAM-1 as slave')
            self.role_var_camera1.set('Slave')
        
        if len(self.ip_var_camera3.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera3.get(), 'thread_socket_set_cam2_as_master', 'set_as_slave')
            self.write_log('set CAM-3 as slave')
            self.role_var_camera3.set('Slave')

        if len(self.ip_var_camera4.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera4.get(), 'thread_socket_set_cam2_as_master', 'set_as_slave')
            self.write_log('set cam4 as slave')
            self.role_var_camera4.set('Slave')

    def thread_socket_set_cam3_as_master(self):
        if len(self.ip_var_camera3.get()) > 0:
            # send command 'set_as_master'
            self.thread_socket_ip_command(self.ip_var_camera3.get(), 'thread_socket_set_cam3_as_master', 'set_as_master')
            self.write_log('set CAM-3 as master')
            self.role_var_camera3.set('Master')
            self.ip_var_master.set(self.ip_var_camera3.get())
            self.lbl_master.configure(bg='lime')
            self.ip_var_master_is_set = True

        if len(self.ip_var_camera1.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera1.get(), 'thread_socket_set_cam3_as_master', 'set_as_slave')
            self.write_log('set cam1 as slave')
            self.role_var_camera1.set('Slave')

        if len(self.ip_var_camera2.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera2.get(), 'thread_socket_set_cam3_as_master', 'set_as_slave')
            self.write_log('set cam2 as slave')
            self.role_var_camera2.set('Slave')


        if len(self.ip_var_camera4.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera4.get(), 'thread_socket_set_cam3_as_master', 'set_as_slave')
            self.write_log('set CAM-4 as slave')
            self.role_var_camera3.set('Slave')


    def thread_socket_set_cam4_as_master(self):
        if len(self.ip_var_camera4.get()) > 0:
            # send command 'set_as_master'
            self.thread_socket_ip_command(self.ip_var_camera4.get(), 'thread_socket_set_cam4_as_master', 'set_as_master')
            self.write_log('set CAM-4 as master')
            self.role_var_camera4.set('Master')
            self.ip_var_master.set(self.ip_var_camera4.get())
            self.lbl_master.configure(bg='lime')
            self.ip_var_master_is_set = True

        if len(self.ip_var_camera1.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera1.get(), 'thread_socket_set_cam4_as_master', 'set_as_slave')
            self.write_log('set CAM-1 as slave')
            self.role_var_camera1.set('Slave')

        if len(self.ip_var_camera2.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera2.get(), 'thread_socket_set_cam4_as_master', 'set_as_slave')
            self.write_log('set CAM-2 as slave')
            self.role_var_camera2.set('Slave')

        if len(self.ip_var_camera3.get()) > 0:
            # send command 'set_as_slave'
            self.thread_socket_ip_command(self.ip_var_camera3.get(), 'thread_socket_set_cam4_as_master', 'set_as_slave')
            self.write_log('set CAM-3 as slave')
            self.role_var_camera3.set('Slave')

    def thread_socket_set_host_dir_cam(self):
        pass


#   以下是与按钮绑定的函数

    def socket_exposure(self):
        _thread.start_new_thread( self.thread_socket_command, ('thread_command','exposure') )

    def socket_master_exposure(self):
        if self.ip_var_master_is_set:
            # _thread.start_new_thread( self.thread_socket_ip_command, (self.ip_var_master.get(), 'socket_master_exposure','exposure') )
            # _thread.start_new_thread( self.thread_socket_ip_exposure, (self.ip_var_master.get(), 'socket_master_exposure','readout') )

            _thread.start_new_thread( self.thread_socket_ip_exposure, (self.ip_var_camera1.get(), 'socket_master_exposure','readout') )
            _thread.start_new_thread( self.thread_socket_ip_exposure, (self.ip_var_camera2.get(), 'socket_master_exposure','readout') )
            _thread.start_new_thread( self.thread_socket_ip_exposure, (self.ip_var_camera3.get(), 'socket_master_exposure','readout') )
            _thread.start_new_thread( self.thread_socket_ip_exposure, (self.ip_var_camera4.get(), 'socket_master_exposure','readout') )
        else:
            self.write_log('**** IP of master CAM has not been set ****')

    def socket_abort(self):
        # _thread.start_new_thread( self.thread_socket_command, ('thread_command','abort') )
        if self.ip_var_master_is_set:
            _thread.start_new_thread( self.thread_socket_ip_command, (self.ip_var_master.get(),'thread_command','abort') )
        else:
            self.write_log('**** IP of master CAM has not been set ****')

    def socket_check_host_connection(self):
        _thread.start_new_thread( self.thread_check_host_connection, () )

    def socket_find_camera(self):
        _thread.start_new_thread( self.thread_find_camera, () )

    def socket_set_exposure_time(self):
        # TODO: 该函数执行后,socket服务端子线程未退出.
        # 问题已经查明,是因为服务端返回的信息与cmd+'_ok'对不上
        if self.ip_var_master_is_set:
            cmd = 'set_exp_t'
            expt = float(self.var_expt.get())
            if expt > 0:
                cmd = cmd + '|{}'.format(expt)
            self.write_log('set expsoure time to {} seconds'.format(expt))
            self.write_log('[DEBUG] self.ip_var_master.get() is : {}'.format(self.ip_var_master.get()))
            _thread.start_new_thread( self.thread_socket_ip_command, (self.ip_var_master.get(), 'socket_set_exposure_time',cmd) )
        else:
            self.write_log('**** IP of master CAM has not been set ****')

    def socket_set_linuxhost_bindir_cam1(self):
        self.bindir_camera1_val.set(self.linux_host_bindir.get())
        ip = self.host_ip_var.get()
#        cmd = 'set_host_dir|{}:{}'.format(ip, self.bindir_camera1_val.get())
        cmd = 'set_host_dir|' + ip + ':' + self.bindir_camera1_val.get() + ' /mnt'
        self.write_log('sending cmd: {} to socket server'.format(cmd))
        _thread.start_new_thread( self.thread_socket_ip_command, (self.ip_var_master.get(), 'socket_set_linuxhost_bindir_cam1',cmd) )

    def socket_set_linuxhost_bindir_cam2(self):
        self.bindir_camera2_val.set(self.linux_host_bindir)
        cmd = 'set_host_dir' + '|' + self.bindir_camera2_val.get()
        _thread.start_new_thread( self.thread_socket_ip_command, (self.ip_var_master.get(), 'socket_set_linuxhost_bindir_cam2',cmd) )

    def socket_set_linuxhost_bindir_cam3(self):
        self.bindir_camera3_val.set(self.linux_host_bindir)
        cmd = 'set_host_dir' + '|' + self.bindir_camera3_val.get()
        _thread.start_new_thread( self.thread_socket_ip_command, (self.ip_var_master.get(), 'socket_set_linuxhost_bindir_cam3',cmd) )

    def socket_set_linuxhost_bindir_cam4(self):
        self.bindir_camera4_val.set(self.linux_host_bindir)
        cmd = 'set_host_dir' + '|' + self.bindir_camera4_val.get()
        _thread.start_new_thread( self.thread_socket_ip_command, (self.ip_var_master.get(), 'socket_set_linuxhost_bindir_cam4',cmd) )

    def socket_set_cam1_as_master(self):
        _thread.start_new_thread( self.thread_socket_set_cam1_as_master, () )

    def socket_set_cam2_as_master(self):
        _thread.start_new_thread( self.thread_socket_set_cam2_as_master, () )

    def socket_set_cam3_as_master(self):
        _thread.start_new_thread( self.thread_socket_set_cam3_as_master, () )

    def socket_set_cam4_as_master(self):
        _thread.start_new_thread( self.thread_socket_set_cam4_as_master, () )

##########################
    def run(self):
        self.window.mainloop()
